package cn.lili.modules.serviceimpl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.SceneEnums;
import cn.lili.common.utils.BeanUtil;
import cn.lili.common.utils.SnowFlake;
import cn.lili.common.utils.StringUtils;
import cn.lili.common.vo.PageVO;
import cn.lili.modules.mapper.UrbanSubstationMapper;
import cn.lili.modules.member.client.UserClient;
import cn.lili.modules.member.entity.dos.User;
import cn.lili.modules.member.entity.dto.UserInfoDTO;
import cn.lili.modules.message.entity.dos.Message;
import cn.lili.modules.message.entity.enums.MessageSendClient;
import cn.lili.modules.message.entity.enums.RangeEnum;
import cn.lili.modules.operationcenter.client.OperationCenterClient;
import cn.lili.modules.operationcenter.entity.dos.OperationCenter;
import cn.lili.modules.service.UrbanSubstationService;
import cn.lili.modules.store.entity.enums.StoreStatusEnum;
import cn.lili.modules.system.client.IRegionClient;
import cn.lili.modules.system.entity.dos.Region;
import cn.lili.modules.urbansubstation.entity.dos.UrbanSubstation;
import cn.lili.modules.urbansubstation.entity.dto.UrbanSubstationDTO;
import cn.lili.modules.urbansubstation.entity.dto.UrbanSubstationEditDTO;
import cn.lili.modules.urbansubstation.entity.dto.UrbanSubstationSearchPageParams;
import cn.lili.modules.urbansubstation.entity.dto.UrbanSubstationSearchParams;
import cn.lili.modules.urbansubstation.entity.vos.UrbanSubstationVo;
import cn.lili.mybatis.util.PageUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.spi.ServiceRegistry;
import java.util.List;
import java.util.Objects;

@Service
@RequiredArgsConstructor
public class UrbanSubstationServiceImpl extends ServiceImpl<UrbanSubstationMapper, UrbanSubstation> implements UrbanSubstationService {

    private final Cache cache;

    private final UserClient userClient;

    private final IRegionClient regionClient;

    private final OperationCenterClient operationCenterClient;

    @Override
    public UrbanSubstation getUrbanSubstation(String userId) {
        UrbanSubstation urbanSubstation = (UrbanSubstation) cache.get(CachePrefix.URBAN_SUBSTATION.getPrefix() + userId);
        if (urbanSubstation == null) {
            LambdaQueryWrapper<UrbanSubstation> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UrbanSubstation::getUserId, userId);
            queryWrapper.last("limit 1");
            urbanSubstation = this.baseMapper.selectOne(queryWrapper);
            cache.put(CachePrefix.URBAN_SUBSTATION.getPrefix() + userId, urbanSubstation, 7200L);
        }
        return urbanSubstation;

    }

    @Override
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public UrbanSubstation edit(UrbanSubstationEditDTO urbanSubstationEditDTO) {
        if (urbanSubstationEditDTO != null) {
            LambdaQueryWrapper<UrbanSubstation> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UrbanSubstation::getUrbanName, urbanSubstationEditDTO.getUrbanName());
            List<UrbanSubstation> list = this.list(queryWrapper);
            if (ObjectUtil.isNotNull(list) && !list.isEmpty()) {
                list.forEach(urbanSubstation -> {
                    if (!urbanSubstation.getId().equals(urbanSubstationEditDTO.getId())) {
                        throw new ServiceException(ResultCode.URBAN_NAME_EXIST_ERROR);
                    }
                });
            }

            UrbanSubstation urbanSubstation = this.getById(urbanSubstationEditDTO.getId());
            if (urbanSubstation != null) {
                BeanUtil.copyProperties(urbanSubstationEditDTO, urbanSubstation);
                urbanSubstation.setId(urbanSubstationEditDTO.getId());
                if (StoreStatusEnum.REFUSED.name().equals(urbanSubstation.getStatus())) {
                    urbanSubstation.setStatus(StoreStatusEnum.APPLYING.name());
                }

                this.updateById(urbanSubstation);
            }
            cache.remove(CachePrefix.URBAN_SUBSTATION.getPrefix() + urbanSubstationEditDTO.getId());
            return urbanSubstation;
        } else {
            throw new ServiceException(ResultCode.URBAN_NOT_EXIST);
        }
    }

    @Override
    public UrbanSubstation add(UrbanSubstationDTO urbanSubstationDTO) {
        if (!SceneEnums.MANAGER.equals(UserContext.getCurrentUser().getScene())) {
            throw new ServiceException(ResultCode.URBAN_ADD_ERROR);
        }

        LambdaQueryWrapper<UrbanSubstation> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(UrbanSubstation::getUrbanName, urbanSubstationDTO.getUrbanName());
        List<UrbanSubstation> list = this.list(queryWrapper);
        if (ObjectUtil.isNotNull(list) && !list.isEmpty()) {
            throw new ServiceException(ResultCode.URBAN_NAME_EXIST_ERROR);
        }

        queryWrapper.clear();
        queryWrapper.eq(UrbanSubstation::getAreaId, urbanSubstationDTO.getAreaId());
        List<UrbanSubstation> list2 = this.list(queryWrapper);
        if (ObjectUtil.isNotNull(list2) && !list2.isEmpty()) {
            throw new ServiceException(ResultCode.URBAN_AREA_EXIST_ERROR);
        }

        UrbanSubstation urbanSubstation = new UrbanSubstation(urbanSubstationDTO);
        urbanSubstation.setId(SnowFlake.getIdStr());
        Region region = regionClient.getRegionById(urbanSubstation.getAreaId());
        Region parentRegion = regionClient.getRegionById(region.getParentId());
        if (null != parentRegion) {
            urbanSubstation.setProvinceId(parentRegion.getId());
            urbanSubstation.setProvinceName(parentRegion.getName());
        }


        User user = userClient.register(UserInfoDTO.builder()
                .username(urbanSubstationDTO.getUsername())
                .password(new BCryptPasswordEncoder().encode(urbanSubstationDTO.getPassword()))
                .mobile(urbanSubstationDTO.getUrbanPhone())
                .extendName(urbanSubstationDTO.getUrbanName())
                .nickName("用户" + urbanSubstationDTO.getUrbanPhone())
                .scene(SceneEnums.valueOf(urbanSubstationDTO.getScene()))
                .extendId(urbanSubstation.getId())
                .isSuper(true)
                .shopkeeper(true)
                .build());

        urbanSubstation.setUserId(user.getId());
        this.save(urbanSubstation);
        return urbanSubstation;
    }

    @Override
    public Page<UrbanSubstationVo> findByConditionPage(UrbanSubstationSearchParams urbanSubstationSearchParams, PageVO page) {
        QueryWrapper queryWrapper = urbanSubstationSearchParams.queryWrapper();
        return this.baseMapper.findByConditionPage(PageUtil.initPage(page), queryWrapper);
    }

    @Override
    public UrbanSubstation getUrbanSubstationById(String id) {
        UrbanSubstation urbanSubstation = (UrbanSubstation) cache.get(CachePrefix.URBAN_SUBSTATION.getPrefix() + id);
        if (urbanSubstation == null) {
            urbanSubstation = getById(id);
            cache.put(CachePrefix.URBAN_SUBSTATION.getPrefix() + id, urbanSubstation, 7200L);
        }
        return urbanSubstation;
    }

    @Override
    public UrbanSubstation getByAddressId(String areaId) {
        LambdaQueryWrapper<UrbanSubstation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UrbanSubstation::getAreaId, areaId);
        queryWrapper.last("limit 1");
        UrbanSubstation urbanSubstation = this.baseMapper.selectOne(queryWrapper);
        return urbanSubstation;
    }

    @Override
    public void disable(String id) {
        UrbanSubstation urbanSubstation = this.getById(id);
        if (urbanSubstation != null) {
            urbanSubstation.setStatus(StoreStatusEnum.CLOSED.value());
            this.updateById(urbanSubstation);
            cache.remove(CachePrefix.URBAN_SUBSTATION.getPrefix() + id);
            Message message = new Message();
            message.setMessageRange(RangeEnum.APPOINT.name());
            message.setMessageClient(MessageSendClient.STORE.name());
            return;
        }
        throw new ServiceException(ResultCode.URBAN_NOT_EXIST);
    }

    @Override
    public void enable(String id, String status) {
        UrbanSubstation urbanSubstation = this.getById(id);
        if (urbanSubstation != null) {
            if (CharSequenceUtil.isNotEmpty(status)) {
                urbanSubstation.setStatus(status);
            }else {
                urbanSubstation.setStatus(StoreStatusEnum.OPEN.value());
            }

            this.updateById(urbanSubstation);
            cache.remove(CachePrefix.URBAN_SUBSTATION.getPrefix() + id);
            return;
        }
        throw new ServiceException(ResultCode.URBAN_NOT_EXIST);
    }

    @Override
    public void delete(String id) {
        UrbanSubstation urbanSubstation = this.getById(id);
        if (urbanSubstation != null) {
            this.removeById(id);
            //删除用户账户
            this.userClient.deleteUserByExtId(id);
            return;
        }
        throw new ServiceException(ResultCode.URBAN_NOT_EXIST);
    }

    @Override
    public UrbanSubstation getById(String id) {
        UrbanSubstation urbanSubstation = this.baseMapper.selectById(id);
        return urbanSubstation;
    }

    @Override
    public List<UrbanSubstation> select(String name) {
        LambdaQueryWrapper<UrbanSubstation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(name)) {
            lambdaQueryWrapper.like(UrbanSubstation::getAreaName, name);
        }
        lambdaQueryWrapper.select(UrbanSubstation::getUserId, UrbanSubstation::getAreaName);
        return super.list(lambdaQueryWrapper);
    }

    @Override
    public Page<UrbanSubstation> getPageByRegionIds (UrbanSubstationSearchPageParams searchPageParams) {
        LambdaQueryWrapper<UrbanSubstation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotEmpty(searchPageParams.getUrbanSubstationSearchParams().getProvinceId())) {
            lambdaQueryWrapper.eq(UrbanSubstation::getProvinceId, searchPageParams.getUrbanSubstationSearchParams().getProvinceId());
        }
        if (StringUtils.isNotEmpty(searchPageParams.getUrbanSubstationSearchParams().getUrbanName())) {
            lambdaQueryWrapper.like(UrbanSubstation::getUrbanName, searchPageParams.getUrbanSubstationSearchParams().getUrbanName());
        }
        if (StringUtils.isNotEmpty(searchPageParams.getUrbanSubstationSearchParams().getAreaId())) {
            lambdaQueryWrapper.like(UrbanSubstation::getAreaId, searchPageParams.getUrbanSubstationSearchParams().getAreaId());
        }
        if (CollectionUtil.isNotEmpty(searchPageParams.getUrbanSubstationSearchParams().getRegionList())) {
            lambdaQueryWrapper.in(UrbanSubstation::getAreaId, searchPageParams.getUrbanSubstationSearchParams().getRegionList());
        }
        return this.baseMapper.selectPage(PageUtil.initPage(searchPageParams.getPage()), lambdaQueryWrapper);
    }


    /**
     * 获取运营中心账号下的城市分站下拉框
     *
     * @return
     */
    @Override
    public List<UrbanSubstation> getOperationCenterUrbanSubstationList() {
        AuthUser authUser = UserContext.getCurrentUser();
        OperationCenter operationCenter = operationCenterClient.getOperationCenter(authUser.getId());

        if (ObjectUtil.isNull(operationCenter)) {
            throw new ServiceException("当前登录账号未找到相关运营中心信息");
        }
        //group by 查询城市分站
        List<UrbanSubstation> urbanSubstationList = this.baseMapper.getOperationCenterUrbanSubstationList(operationCenter.getProvinceId());
        return urbanSubstationList;
    }
}
